﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using PServiceBus.Core.Interface;
using System.Collections;
using PServiceBus.Core.Runtime;
using PServiceBus.Core.Runtime.Configuration;

namespace PServiceBus.Core.Manager {
    /// <summary>
    /// Factory for IObjectManager creation
    /// </summary>
    /// <typeparam name="TObject">The type of the object that is marked as identifiable.</typeparam>
    public class ObjectManager<TObject> where TObject : class, IIdentifiable {
        /// <summary>
        /// Return a cached instance of IObjectManager[TObject]
        /// </summary>
        public static IObjectManager<TObject> Instance {
            get {
                var obj = PServiceBus.Core.Runtime.ServiceLocator<IObjectManager<TObject>>.Get();
                if (obj == null) {
                    obj = Create(null);
                    PServiceBus.Core.Runtime.ServiceLocator<IObjectManager<TObject>>.Set(obj);
                }
                return obj;
            }
        }
        /// <summary>
        /// Return new instance of IObjectManager[TObject]
        /// </summary>
        /// <param name="endpoint"></param>
        /// <returns></returns>
        public static IObjectManager<TObject> Create(string endpoint) {
            return Create(endpoint, null);
        }

        /// <summary>
        /// Return new instance of IObjectManager[TObject]
        /// </summary>
        /// <param name="endpoint"></param>
        /// <param name="endpointAlias"></param>
        /// <returns></returns>
        public static IObjectManager<TObject> Create(string endpoint, string endpointAlias) {
            var objProviderType = ConfigurationProvider.ObjectProviderType;
            var hasEndpoint = typeof(IHaveEndpoint).IsAssignableFrom(objProviderType) && endpoint != null;
            var obj = new ObjectManagerBase<TObject>() {
                Provider = Activator.CreateInstance(objProviderType.MakeGenericType(typeof(TObject))) as IObjectProvider<TObject>
            };
            obj.Provider.IDFunc = o => o.ID;
            obj.Provider.DeleteObjectOnRead = typeof(IDeleteable).IsAssignableFrom(typeof(TObject));
            obj.Provider.AppendTypeNameToEndpoint = true;
            obj.Provider.Endpoint = endpoint ?? ConfigurationProvider.Address;
            obj.Provider.EndpointAlias = endpointAlias;
            
            if (!hasEndpoint) {
                var tempObj = PServiceBus.Core.Runtime.ServiceLocator<IObjectManager<TObject>>.Get();
                if (tempObj == null) PServiceBus.Core.Runtime.ServiceLocator<IObjectManager<TObject>>.Set(obj);
                return PServiceBus.Core.Runtime.ServiceLocator<IObjectManager<TObject>>.Get();
            }
            return obj;
        }
    }
}
